package com.violet.myorm.core.execute;

import com.violet.myorm.annotations.ManyKey;
import com.violet.myorm.core.combination.DeleteCombination;
import com.violet.myorm.core.condition.LambdaWhere;
import com.violet.myorm.core.foreign.ManyForeign;
import com.violet.myorm.core.source.Reflect;
import com.violet.myorm.core.sql.DeleteSql;
import com.violet.myorm.utils.SqlUtils;

import java.lang.reflect.Field;
import java.util.List;

public class Delete<E>
    extends BaseExecute
    implements DeleteCombination<E, Delete<E>>
{
    private final Class<E> clazz;
    private LambdaWhere<E> where;

    public Delete(Class<E> clazz) {
        this.clazz = clazz;
        this.where = new LambdaWhere<>();
    }

    @Override
    public int executeDelete() {
        // 1. 查看当前要删除的数据, 有没有一对多的关联
        for (Field foreignField : Reflect.getForeignFields(clazz)) {
            if (foreignField.isAnnotationPresent(ManyKey.class)) {
                // 查看关联是级联删除还是保留
                ManyKey manyKey = foreignField.getAnnotation(ManyKey.class);
                List<E> execute = new Query<>(clazz).where(this.where).executeQuery();
                switch (manyKey.state()) {
                    case CASCADE -> execute.forEach(e -> cascade(e, foreignField));
                    case SET_NULL -> execute.forEach(e -> setNull(e, foreignField));
                }
            }
        }
        DeleteSql delete = SqlUtils.createDelete(clazz, where.getWhere());
        return executeDelete(delete, where.getWhereParams());
    }

    private void cascade(E e, Field field) {
        try {
            ManyForeign manyForeign = (ManyForeign) field.get(e);
            manyForeign.executeDelete();
        }
        catch (IllegalAccessException ex) {
            throw new RuntimeException(ex);
        }
    }

    private void setNull(E e, Field field) {
        try {
            ManyForeign manyForeign = (ManyForeign) field.get(e);
            manyForeign.setNull();
        }
        catch (IllegalAccessException ex) {
            throw new RuntimeException(ex);
        }
    }

    @Override
    public Delete<E> where(LambdaWhere<E> condition) {
        this.where = condition;
        return this;
    }
}
